package com.mini.mybatis.mybatisministep03.builder.xml;

import com.mini.mybatis.mybatisministep03.builder.BaseBuilder;
import com.mini.mybatis.mybatisministep03.io.Resources;
import com.mini.mybatis.mybatisministep03.mapping.MappedStatement;
import com.mini.mybatis.mybatisministep03.mapping.SqlCommandType;
import com.mini.mybatis.mybatisministep03.sqlsession.configuration.Configuration;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import org.xml.sax.InputSource;

import java.io.Reader;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class XmlConfigBuilder extends BaseBuilder {

    private Element rootElement;

    public XmlConfigBuilder(Reader reader) {

        // 调用父类初始化configuration
        super(new Configuration());

        // 利用dom4j解析xml
        SAXReader saxReader = new SAXReader();

        try {
            Document document = saxReader.read(new InputSource(reader));
            // 获取配置文件中的根节点
            rootElement = document.getRootElement();
        } catch (DocumentException e) {
            throw new RuntimeException(e);
        }
    }


    /**
     * 解析mybatis全局配置文件,主要解析mappers
     * @return
     */
    public Configuration parse(){

        try {
            // 当前只解析mapper标签
            mapperElement(rootElement.element("mappers"));
        } catch (Exception e) {
            throw new RuntimeException(e);
        }

        return configuration;
    }

    /**
     * <mappers>
     *      <mapper resource="mapper/UserMapper.xml"/>
     *      <mapper resource="mapper/PetMapper.xml"/>
     *  </mappers>
     *
     * 读取每个mapper.xml并解析，
     * @param mappers
     * @throws Exception
     */
    private void mapperElement(Element mappers) throws Exception{

        List<Element> mapperList = mappers.elements("mapper");

        for (Element e : mapperList) {
            String resource = e.attributeValue("resource");
            Reader reader = Resources.getResourceAsReader(resource);
            SAXReader saxReader = new SAXReader();
            Document document = saxReader.read(reader);
            Element root = document.getRootElement();

            // 命名空间
            String namespace = root.attributeValue("namespace");

            // 解析select标签
            List<Element> selectNodes = root.elements("select");
            for (Element selectNode : selectNodes) {
                String id = selectNode.attributeValue("id");
                String parameterType = selectNode.attributeValue("parameterType");
                String resultType = selectNode.attributeValue("resultType");
                String sql = selectNode.getText();

                // ? 匹配参数 #{type}
                Map<Integer,String>  parameter = new HashMap<>();
                Pattern pattern = Pattern.compile("(#\\{(.*?)})");
                Matcher matcher = pattern.matcher(sql);
                for (int i = 1; matcher.find(); i++) {
                    String g1 = matcher.group(1); // #{type}
                    String g2 = matcher.group(2); // type
                    parameter.put(i, g2); // parameter.put(1, type);
                    sql = sql.replace(g1, "?");
                }

                String msId = namespace + "." + id;
                String nodeName = selectNode.getName();
                SqlCommandType sqlCommandType = SqlCommandType.valueOf(nodeName.toUpperCase(Locale.ENGLISH));
                MappedStatement mappedStatement = new MappedStatement.Builder(configuration, msId, sqlCommandType, parameterType, resultType, sql, parameter).build();
                configuration.addMappedStatement(mappedStatement);
            }

            // 注册mapper映射器
            configuration.addMapper(Resources.classForName(namespace));

        }
    }
}
